#include "historymessagewidget.h"

#include <QPushButton>
#include <QLabel>
#include <QScrollArea>
#include <QScrollBar>
#include <QFileDialog>
#include "debug.h"
#include "model/datacenter.h"
using namespace model;
#include "soundrecorder.h"

/**********************************************************************************************
 * 表示一条历史消息
 **********************************************************************************************/
HistoryItem *HistoryItem::makeHistoryItem(const MessageInfo &message)
{
    // 1. 创建出对象
    HistoryItem* item = new HistoryItem();
    item->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);

    // 2. 创建布局
    QGridLayout* layout = new QGridLayout();
    layout->setVerticalSpacing(0);
    layout->setHorizontalSpacing(10);
    layout->setContentsMargins(0, 0, 0, 0);
    item->setLayout(layout);

    // 3. 创建头像
    QPushButton* avatarBtn = new QPushButton();
    avatarBtn->setFixedSize(40, 40);
    avatarBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    avatarBtn->setIconSize(QSize(40, 40));
    // 当前消息发送者的头像
    avatarBtn->setIcon(message.userInfo.avatar);
    avatarBtn->setStyleSheet("QPushButton { border: none; }");

    // 4. 创建昵称和时间
    QLabel* nameLabel = new QLabel();
    nameLabel->setText(message.userInfo.nickName + " | " + message.time);
    nameLabel->setFixedHeight(20);   // 高度设置为头像高度的一半
    nameLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);

    // 5. 消息内容部分
    QWidget* contentWidget = nullptr;
    if (message.messageType == model::TEXT_TYPE) {
        // 文本消息
        QLabel* label = new QLabel();
        label->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
        label->setWordWrap(true);
        label->setText(QString(message.content));
        label->adjustSize();	// 设置让 label 能够自动调整大小
        contentWidget = label;
    } else if (message.messageType == model::IMAGE_TYPE) {
        // 图片消息
        contentWidget = new ImageButton(message.fileId,message.content);
    } else if (message.messageType == model::FILE_TYPE) {
        // 文件消息
        contentWidget = new FileLabel(message.fileId,message.content,message.fileName);
    } else if (message.messageType == model::SPEECH_TYPE) {
        // 语音消息
        contentWidget = new SoundLabel(message.fileId,message.content);
    } else {
        LOG() << "错误的消息类型! messageType=" << message.messageType;
    }

    // 6. 把上述控件添加到布局中
    layout->addWidget(avatarBtn, 0, 0, 2, 1);
    layout->addWidget(nameLabel, 0, 1, 1, 1);
    layout->addWidget(contentWidget, 1, 1, 5, 1);

    return item;
}


/**********************************************************************************************
 * 表示历史消息展示区
 **********************************************************************************************/
HistoryMessageWidget::HistoryMessageWidget(QWidget *parent)
    :QDialog(parent)
{
    // 1. 设置窗口本身属性
    this->setFixedSize(550, 600);
    this->setWindowTitle("历史消息");
    this->setWindowIcon(QIcon(":/resource/HistoryMessageWidget.png"));
    this->setStyleSheet("QWidget { background-color: rgb(255, 255, 255); }");
    this->setAttribute(Qt::WA_DeleteOnClose);

    // 2. 创建布局管理器.
    QGridLayout* layout = new QGridLayout();
    layout->setSpacing(10);
    layout->setContentsMargins(30, 30, 30, 0);
    this->setLayout(layout);

    // 3. 创建单选按钮
    keyRadioBtn = new QRadioButton();
    timeRadioBtn = new QRadioButton();
    keyRadioBtn->setText("按关键词查询");
    timeRadioBtn->setText("按时间查询");
    // 默认按照关键词查询
    keyRadioBtn->setChecked(true);
    layout->addWidget(keyRadioBtn, 0, 0, 1, 2);
    layout->addWidget(timeRadioBtn, 0, 2, 1, 2);

    // 4. 创建搜索框
    searchEdit = new QLineEdit();
    searchEdit->setFixedHeight(40);
    searchEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    searchEdit->setPlaceholderText("要搜索的关键词");
    searchEdit->setStyleSheet("QLineEdit { border: none; border-radius: 10px; background-color: rgb(240, 240, 240); font-size: 12px; padding-left: 10px; }");
    layout->addWidget(searchEdit, 1, 0, 1, 8);

    // 5. 创建搜索按钮
    QPushButton* searchBtn = new QPushButton();
    searchBtn->setFixedSize(40, 40);
    searchBtn->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    searchBtn->setIconSize(QSize(30, 30));
    searchBtn->setIcon(QIcon(":/resource/search.png"));
    QString btnStyle = "QPushButton { border: none; background-color: rgb(240, 240, 240); border-radius: 10px; }";
    btnStyle += "QPushButton:pressed { background-color: rgb(220, 220, 220); }";
    searchBtn->setStyleSheet(btnStyle);
    layout->addWidget(searchBtn, 1, 8, 1, 1);

    // 6. 创建时间相关的部分控件, 初始情况下要隐藏
    QLabel* begTag = new QLabel();
    begTag->setText("开始时间");
    QLabel* endTag = new QLabel();
    endTag->setText("结束时间");
    begTimeEdit = new QDateTimeEdit();
    endTimeEdit = new QDateTimeEdit();
    begTimeEdit->setFixedHeight(40);
    endTimeEdit->setFixedHeight(40);
    begTag->hide();
    endTag->hide();
    begTimeEdit->hide();
    endTimeEdit->hide();

    // 7. 创建滚动区域
    initScrollArea(layout);

    // 8. 设置槽函数
    connect(keyRadioBtn, &QRadioButton::clicked, this, [=]() {
        // 把时间相关的控件, 隐藏起来
        layout->removeWidget(begTag);
        layout->removeWidget(begTimeEdit);
        layout->removeWidget(endTag);
        layout->removeWidget(endTimeEdit);
        begTag->hide();
        begTimeEdit->hide();
        endTag->hide();
        endTimeEdit->hide();

        // 把关键词搜索框显示加入布局
        layout->addWidget(searchEdit, 1, 0, 1, 8);
        searchEdit->show();
        this->clear();
    });

    connect(timeRadioBtn, &QRadioButton::clicked, this, [=]() {
        // 关键词搜索框隐藏并从布局中删除掉.
        layout->removeWidget(searchEdit);
        searchEdit->hide();

        // 把时间相关的控件, 添加到布局中, 并且进行显示.
        layout->addWidget(begTag, 1, 0, 1, 1);
        layout->addWidget(begTimeEdit, 1, 1, 1, 3);
        layout->addWidget(endTag, 1, 4, 1, 1);
        layout->addWidget(endTimeEdit, 1, 5, 1, 3);
        begTag->show();
        begTimeEdit->show();
        endTag->show();
        endTimeEdit->show();
        this->clear();
    });

    connect(searchBtn,&QPushButton::clicked,this,&HistoryMessageWidget::clickSearchBtn);


#ifdef TEST_UI
    for (int i = 0; i < 30; ++i) {
        // 注意此处代码和前面的差别.
        // 前面有个代码, UserInfo 必须要 new 出来才能构造. 当时 Item 对象里, 持有了 const UserInfo& , 不是 new 的话
        // 就可能使引用指向的对象失效的.
        // 此处后续的代码, 都是按照传值的方式来使用 message 的内容, 不 new 也行.
        model::UserInfo sender;
        sender.userId = "";
        sender.nickName = "张三" + QString::number(i);
        sender.avatar = QIcon(":/resource/lion.png");
        sender.description = "";
        sender.phoneNumber = "18612345678";
        model::MessageInfo message = MessageInfo::makeMessage(model::TEXT_TYPE, "", sender, QString("消息内容" + QString::number(i)).toUtf8(), "");
        this->addHistoryMessage(message);
    }
#endif
}

void HistoryMessageWidget::clickSearchBtn()
{
    DataCenter* dataCenter = DataCenter::getInstance();
    connect(dataCenter,&DataCenter::searchMessageDone,this,&HistoryMessageWidget::clickSearchBtnDone,Qt::UniqueConnection);
    //根据当前的选项：时间/关键字
    if(keyRadioBtn->isChecked())
    {
        //按关键字搜索
        const QString& searchKey = searchEdit->text();
        if(searchKey.isEmpty())
        {
            return;
        }
        dataCenter->getHistoryMessageByKeyAsync(searchKey);
    }
    else
    {
        //按时间搜索
        auto beginTime = begTimeEdit->dateTime();
        auto endTime = endTimeEdit->dateTime();
        if(beginTime >= endTime)
        {
            Toast::showMessage("时间错误，开始时间必须小于结束时间!");
            return;
        }

        dataCenter->getHistoryMessageByTimeAsync(beginTime,endTime);
    }
}

void HistoryMessageWidget::clickSearchBtnDone()
{
    DataCenter* dataCenter = DataCenter::getInstance();
    QList<MessageInfo>* searchRet = dataCenter->getSearchMessageResult();

    if(searchRet == nullptr)
    {
        return;
    }

    this->clear();
    for(const auto& m : *searchRet)
    {
        this->addHistoryMessage(m);
    }
}

void HistoryMessageWidget::addHistoryMessage(const MessageInfo &message)
{
    HistoryItem* item = HistoryItem::makeHistoryItem(message);
    container->layout()->addWidget(item);
}

void HistoryMessageWidget::clear()
{
    QVBoxLayout* layout = dynamic_cast<QVBoxLayout*>(container->layout());
    for (int i = layout->count() - 1; i >= 0; --i) {
        // 之前使用的是 takeAt. 效果和这个是一样的.
        QWidget* w = layout->itemAt(i)->widget();
        if (w == nullptr) {
            continue;
        }
        layout->removeWidget(w);
        w->deleteLater();
    }
}

void HistoryMessageWidget::initScrollArea(QGridLayout *layout)
{
    // 1. 创建滚动区域对象
    QScrollArea* scrollArea = new QScrollArea();
    scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
    scrollArea->setWidgetResizable(true);
    scrollArea->verticalScrollBar()->setStyleSheet("QScrollBar:vertical { width: 2px; background-color: rgb(255, 255, 255); }");
    scrollArea->horizontalScrollBar()->setStyleSheet("QScrollBar:horizontal { height: 0; }");
    scrollArea->setStyleSheet("QScrollArea { border: none; }");

    // 2. 创建 QWidget, 持有要加入的新的内容
    container = new QWidget();
    scrollArea->setWidget(container);

    // 3. 创建 container 中的布局管理器.
    QVBoxLayout* vlayout = new QVBoxLayout();
    vlayout->setSpacing(10);
    vlayout->setContentsMargins(0, 0, 0, 0);
    vlayout->setAlignment(Qt::AlignTop);
    container->setLayout(vlayout);

    // 4. 把滚动区加入到整个 layout 中
    layout->addWidget(scrollArea, 2, 0, 1, 9);
}


/**********************************************************************************************
 * 针对图片消息
 **********************************************************************************************/
ImageButton::ImageButton(const QString &fileId, const QByteArray &content)
    :fileId(fileId)
{
    this->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
    this->setStyleSheet("QPushButton { border:none; }");
    if (!content.isEmpty()) {
        // 2. 数据如果⾮空, 则直接设置数据
        updateUI(fileId, content);
    } else {
        DataCenter* dataCenter = DataCenter::getInstance();
        connect(dataCenter, &DataCenter::getSingleFileDone, this,&ImageButton::updateUI);
        dataCenter->getSingleFileAsync(fileId);
    }
}

void ImageButton::updateUI(const QString &fileId, const QByteArray &content)
{
    if (fileId != this->fileId) {
        return;
    }
    QImage image;
    image.loadFromData(content);
    QPixmap pixmap = QPixmap::fromImage(image);
    if (pixmap.width() >= 300) {
        // 适当进⾏缩放
        pixmap = pixmap.scaledToWidth(300);
    }
    this->resize(pixmap.size());
    this->setIconSize(pixmap.size());
    this->setIcon(QIcon(pixmap));
}


/**********************************************************************************************
 * 针对文件历史消息
 **********************************************************************************************/
FileLabel::FileLabel(const QString& fileId, const QByteArray &content, const QString& fileName)
    : fileId(fileId),
    content(content),
    fileName(fileName)
{
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // 设置⼤⼩策略
    this->setWordWrap(true);    // 启⽤⽂本换⾏
    this->adjustSize();         // 调整⼤⼩以适应内容
    this->setAlignment(Qt::AlignTop | Qt::AlignLeft);
    this->setText("[文件] " + fileName);

    //不为空，直接显示
    if (!content.isEmpty())
    {
        return;
    }
    DataCenter* dataCenter = DataCenter::getInstance();
    connect(dataCenter, &DataCenter::getSingleFileDone, this, [=](const QString& fileId, const QByteArray& content)
            {
                if (fileId != this->fileId) {
                    return;
                }
                this->content = content;
                this->loadDone = true;
            });
    dataCenter->getSingleFileAsync(fileId);
}

void FileLabel::mousePressEvent(QMouseEvent *event)
{
    // 1. 判定是否加载完毕
    if (!loadDone) {
        Toast::showMessage("⽂件内容加载中, 请稍后");
        return;
    }
    // 2. 弹出对话框, 选择位置
    QString filePath = QFileDialog::getSaveFileName(this, "另存为",QDir::homePath(), "*");
    if (filePath.isEmpty())
    {
        LOG() << "取消选择保存⽂件的路径";
        return;
    }
    // 3. 保存⽂件
    writeByteArray2File(filePath, content);
}


/**********************************************************************************************
 * 针对语音历史消息
 **********************************************************************************************/
SoundLabel::SoundLabel(const QString& fileId, const QByteArray &content)
    :fileId(fileId)
    ,content(content)
{
    this->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); // 设置⼤⼩策略
    this->setWordWrap(true); // 启⽤⽂本换⾏
    this->adjustSize(); // 调整⼤⼩以适应内容
    this->setAlignment(Qt::AlignTop | Qt::AlignLeft);
    this->setText("[语⾳]");
    if (!content.isEmpty())
    {
        return;
    }
    DataCenter* dataCenter = DataCenter::getInstance();
    connect(dataCenter, &DataCenter::getSingleFileDone, this, [=](const QString& fileId, const QByteArray& content) {
        if (fileId != this->fileId) {
            return;
        }
        this->content = content;
        this->loadDone = true;
    });
    dataCenter->getSingleFileAsync(fileId);
}


void SoundLabel::mousePressEvent(QMouseEvent *event)
{
    if (!loadDone) {
        Toast::showMessage("⽂件内容加载中, 请稍后");
        return;
    }
    SoundRecorder* soundRecorder = SoundRecorder::getInstance();
    soundRecorder->startPlay(content);
}

